﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using System.Threading;
using BaseHelper.Net;
using BaseHelper.Encrypt;

namespace DeviceSDK.LED.ZhongHai.ZhongHai
{
    public class ZHONGHAI_SDK
    {
        private TcpClientHelper _tcp;
        public string _remoteIP;

        private bool _isBusying = false;

        private int _fileBlockSize = 2048;//8100;
        private int _timeout = 3000;
        private byte[] _lastCmdType;
        private byte[] _lastReceiveBuffer;

        private byte[] _waitCmdType;
 
        public bool IsConnected
        {
            get
            {
                if (_tcp!=null &&  _tcp.IsConnected)
                {
                    int mills = 15000 / 10;     //15s等待时间
                    while (_isBusying && mills-- > 0)
                    {
                        Thread.Sleep(10);
                    }
                    return true;
                }
                return false;
              
            }
        }

        public bool Connect(string IP,int Port=8080)
        {
            _remoteIP = IP;
     
            if (_tcp == null)
            {
                _tcp = new TcpClientHelper();
                _tcp.DataArriveEvent += new TcpClientHelper.DataArriveHandler(_socket_DataArreadEvent);
                _tcp.DisconnectEvent+=new TcpClientHelper.DisconnectHandler(_tcp_DisconnectEvent);
            }
            return _tcp.Connect(IP, Port, 8192);
           
            
        }

        public void Close() 
        {
         
            if (_tcp != null)
                _tcp.Close();
        }

        private void _tcp_DisconnectEvent(string remoteIP)
        {
            _tcp = null;
        }




        public bool SetScreenState(bool IsOpen)
        {
            byte[] data=IsOpen?new byte[]{0x00,0xAA}:new byte[]{0x00,0x55};
        
            SendTcpData(CmdType.Set_Screen,data);

            if (WaitData(CmdType.Set_Screen, _timeout))
                return IsOpen ? _lastReceiveBuffer[0] == 0x00 && _lastReceiveBuffer[1] == 0xAA : _lastReceiveBuffer[0] == 0x00 && _lastReceiveBuffer[1] == 0x55;
            else
                return false;
        }

        public int GetScreenState()
        {
            byte[] data = new byte[] { 0x00, 0x10, 0x00, 0x06 };
            SendTcpData(CmdType.Get_Brightness, data);

            if (WaitData(CmdType.Get_Brightness, _timeout))
            {
                return _lastReceiveBuffer[4] == 0x55 ? 0 : 1;
            }
            return -1;
        }

        public bool SetBrightness(int val)
        {

            byte[] data = new byte[] {0xAA,0x00 };
            data[1]=(byte)((int)(31.0*((float)val/100.0)));

            SendTcpData(CmdType.Set_Brightness, data);

            if (WaitData(CmdType.Set_Brightness, _timeout))
                return _lastReceiveBuffer[0]==0xAA && _lastReceiveBuffer[1]==data[1];
            else
                return false;

        }

        public int GetBrightness()
        {
            byte[] data = new byte[] {0x00, 0x10,0x00 ,0x06};
            SendTcpData(CmdType.Get_Brightness,data);
            
            if (WaitData(CmdType.Get_Brightness, _timeout))
            {
                if (_lastReceiveBuffer[0] == 0)
                {
                    int val = (int)_lastReceiveBuffer[2] ;
                    float value = Convert.ToSingle(val) / 31.0f * 100.0f;
                    return (int)value;
                }
            }

            return -1;
        }

        public string GetPlaybillContent()
        {
            byte[] data = new byte[] { 0x03,0x00,0x00,0xFF};
            //00 03 03 00 00 33 04 4A
            SendTcpData(CmdType.Get_PlayList, data);

            string content = "";

            if (WaitData(CmdType.Get_PlayList, _timeout))
            {
                try
                {

                    PlaybillProgramInfo[] pb = DecodeContent(_lastReceiveBuffer);

                    if (pb.Length > 0)
                    {
                        foreach (PlaybillProgramInfo p in pb)
                        {
                            content += string.Format("{0},{1},{2},{3},{4},{5},{6}\r\n",
                                p.PlayTime, p.FontName, p.FontSize, p.FontColor, p.X, p.Y, p.Text
                                );
                        }

                        return content;
                    }
                }
                catch
                {
                    return null;
                }
            }
  

            return null;
        }


        public bool SendPlaybill(PlayBill playbill)
        {
            byte[] data = playbill.Create();

            if (data.Length % 2 == 0)
            { 
                byte[] tmp=new byte[data.Length+1];
                Buffer.BlockCopy(data, 0, tmp, 0, data.Length);
                tmp[tmp.Length - 1] = 0x20;
                data = tmp;
            }

            SendTcpData(CmdType.Set_PlayList,data);

            if (WaitData(CmdType.Set_PlayList, _timeout))
                return _lastReceiveBuffer[0] == data[0] && _lastReceiveBuffer[1]==data[1];
            else
                return false;

        }


        private bool WaitData(byte[] CmdType,int mills)
        {
          
            mills /= 10;
            while (!IsEquals( _lastCmdType, CmdType) && mills-- > 0)
            {
                Thread.Sleep(10);
            }
            _isBusying = false;
            if (IsEquals( _lastCmdType, CmdType))
                return true;
            else
                return false;
           
        }
        
        public void SendTcpData(byte[] cmdType, byte[] data=null)
        {
            if (_tcp == null)
                return;

            _isBusying = true;
            _waitCmdType = cmdType;

            _lastCmdType = null;
            _lastReceiveBuffer = new byte[] { };

            byte[] packData = MakePackage(cmdType, data);
            _tcp.SendBytes(packData);
            //else if(_socketMode==SocketMode.UDP)
            //    _udp.Send(_remoteIP, _udpPort, packData);


        }

        public byte[] MakePackage(byte[] cmdType, byte[] data=null)
        {
            //1默认 2功能 3-4地址 5-6值 7-8CRC
            if (data == null)
                data = new byte[] { };

            byte[] buffer= new byte[1 + cmdType.Length + data.Length + 2];
            
            //1.帧头
            buffer[0] = 0x00;

            //2.命令头
            Buffer.BlockCopy(cmdType, 0, buffer, 1, cmdType.Length);

            //3.数据头
            Buffer.BlockCopy(data, 0, buffer, 1+cmdType.Length, data.Length);


            ushort crc = CRCHelper.CRC16_MODBUS(buffer,buffer.Length-2);
            
            //校验
            buffer[buffer.Length - 2] = (byte)crc;
            buffer[buffer.Length - 1] = (byte)(crc>>8);


            if (data != null)
                buffer = EncodeByte(buffer);

            //string str = ByteHelper.GetStringByByte(buffer);
            //File.AppendAllText("d:\\记录.txt", "【发送】" + str + "\r\n");

            return buffer;
        }

        private byte[] EncodeByte(byte[] data)
        {
            return data;
            if(data==null)
                return null;

            List<byte> lt = new List<byte>();
            foreach (byte b in data)
            {
            if (b == 0x02)
            {
                lt.Add(0x1b);
                lt.Add(0xe7);
            }
            else
              lt.Add(b);
            }
         return lt.ToArray();
    
          
        }

        private byte[] DecodeByte(byte[] data)
        {
            return data;

            List<byte> lt = new List<byte>();
            for (int i = 0; i < data.Length-1; i++)
            {
                if (data[i] == 0x1b && data[i + 1] == 0xe7)
                {
                    lt.Add(0x02);
                    i++;
                }
                else
                    lt.Add(data[i]);

            }

            lt.Add(data[data.Length-1]);
            return lt.ToArray();
        }

        public PlaybillProgramInfo[] DecodeContent(byte[] data)
        {
            List<PlaybillProgramInfo> ltPb = new List<PlaybillProgramInfo>();
            PlaybillProgramInfo program=new PlaybillProgramInfo();
            List<byte> lt = new List<byte>();

            SortedList<int, string> slFontName = new SortedList<int, string>();
            slFontName.Add(0x00, "黑体");
            slFontName.Add(0x01, "楷体");
            slFontName.Add(0x02, "宋体");
            slFontName.Add(0x03, "仿宋");


            SortedList<int, string> slColor = new SortedList<int, string>();
            slColor.Add(0x00, "#FF0000");
            slColor.Add(0x01, "#00FF00");
            slColor.Add(0x02, "#FFFF00");//2是蓝
            slColor.Add(0x03, "#FFFF00");
            slColor.Add(0x04, "#FFFF00");//4是白色

            int programCount = 0;
            try
            {
                for (int i = 0; i < data.Length - 1; i++)
                {
                    if (data[i] == 0x1b && data[i + 1] == 0x37) //字符间距
                    {
                        i += 2;
                    }
                    else if (data[i] == 0x1b && data[i + 1] == 0x36)    //立即显示
                    {
                        if (programCount>= 1)
                        {
                            program.Text = Encoding.Default.GetString(lt.ToArray()).Trim();
                            ltPb.Add(program);
                            lt.Clear();
                        }
                        programCount++;

                        program = new PlaybillProgramInfo();
                        program.IsEffectRand = 0;
                        program.PlayTime =  (int)((int)(data[i + 3]<<8) + data[i + 4]); //300ms，单位10ms

                        i += 4;
                        //0x0D 0x0A代表换行
                        //lt.Add(0x0D);
                        //lt.Add(0x0A);
                    }
                    else if (data[i] == 0x1b && data[i + 1] == 0x35)//字体大小
                    {
                        program.FontSize = (int)data[i + 2];
                        i += 2;
                    }
                    else if (data[i] == 0x1b && data[i + 1] == 0x34)//宋体
                    {
                        program.FontName = slFontName[data[i + 2]];
                        i += 2;

                    }
                    else if (data[i] == 0x1b && data[i + 1] == 0x32)//坐标XY
                    {
                        program.X = (int)((int)(data[i + 2] << 8) + data[i + 3]);
                        program.Y = (int)((int)(data[i + 4] << 8) + data[i + 5]);
                        i += 5;

                    }
                    else if (data[i] == 0x1b && data[i + 1] == 0x31)//字体颜色
                    {
                        program.FontColor = slColor[data[i + 2]];
                        i += 2;
                    }
                    else if (data[i] == 0x1b && data[i + 1] == 0x30)//换行
                    {
                        i++;
                        lt.Add((byte)'\n');
                    }
                    else
                        lt.Add(data[i]);


                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return ltPb.ToArray();

            }

            lt.Add(data[data.Length - 1]);
            program.Text = Encoding.Default.GetString(lt.ToArray()).Replace("\0","").Trim();
            ltPb.Add(program);
           
            return ltPb.ToArray();
        }

        private void _socket_DataArreadEvent(string remoteIp, byte[] buffer, int len)
        {
            //string str = ByteHelper.GetStringByByte(buffer, len);
            //File.AppendAllText("d:\\记录.txt", "【接收】" + str + "\r\n");


            if (buffer[0] != 0x00)
            {
                return;
            }
         

            buffer = DecodeByte(buffer);

            byte[] cmd = new byte[_waitCmdType.Length];
            for(int i=0;i<_waitCmdType.Length;i++)
            {
                cmd[i] = buffer[i + 1];
            }
            
            //是否是等待的数据包
            if (IsEquals(_waitCmdType, cmd))
            {
                byte[] data = new byte[len - 6];
                Buffer.BlockCopy(buffer, 4, data, 0, data.Length);

                _lastReceiveBuffer = data;
                _lastCmdType = cmd;
            }
            else
            {
                //不是等待的丢弃掉
            }
        }

        private bool IsEquals(byte[] src, byte[] dst)
        {

            if (src==null || dst==null || src.Length != dst.Length)
                return false;

            for (int i = 0; i < src.Length; i++)
            {
                if (src[i] != dst[i])
                    return false;
            }

            return true;
        
        }

    }
}
